#pragma once
// #ifndef _TIMER_HPP_
// #define _TIMER_HPP_

#include <iostream>
#include <map>
#include <string>
#include <chrono>
#include <functional>

class Timer{
    public:
        using Clock = std::chrono::high_resolution_clock;
        Timer(){
            restart();
        }

        // return current unix timestamp
        void restart() {
            m_start_time = std::chrono::high_resolution_clock::now();
        }

        // return duration in seconds
        double duration() const {
            auto now = std::chrono::high_resolution_clock::now();   // std::chrono::time_point
            auto m = std::chrono::duration_cast<std::chrono::milliseconds>(now - m_start_time).count();
            return m * 1.0 / 1e6;
        }
    protected:
        std::chrono::time_point<Clock> m_start_time;
};

// Syntax of Lambda functions(expression)
// auto var = []() -> type { }
// auto var要创建的lambda func, auto代表类型由complier决定, var可以看作是func pointer
// [] 是capture list, 在capture list里面传入lambda function周围的参数，lambda func可以使用；
// () 是parameter list, 与普通函数参数列表一样。
// -> type 指定了lambda function返回的参数类型

class GuardedTimer : public Timer {
    public:
        GuardedTimer(const std::string& msg, bool enabled=true):
            GuardedTimer([msg](double duration){    // lambda expression
                std::cout << msg << ": " << std::to_string(duration * 1000.) << "milliseconds." << std::endl;
            })
            {enabled_ = enabled;}

        GuardedTimer(const char* msg, bool enabled=true):
            GuardedTimer(std::string(msg), enabled) {}
        
        GuardedTimer(std::function<void(double)> callback):m_callback(callback)
        {}

        ~GuardedTimer(){
            if (enabled_)
                m_callback(duration());
        }

    protected:
        bool enabled_;
        std::function<void(double)> m_callback;
};

// record the total running time of a region across the lifecycle of the whole program
// call TotalTimer::print() before exiting main()
class TotalTimer {
    public:
        TotalTimer(const std::string& msg): msg(msg) {
                timer.restart();
        }
        ~TotalTimer();

        static void print();

        std::string msg;
        Timer timer;

        static std::map<std::string, std::pair<int, double>> rst;
};

// build a global instance of this class, to call print() before program exit.
struct TotalTimerGlobalGuard {
    ~TotalTimerGlobalGuard() {TotalTimer::print();}
};

// __func__ : return the name of the calling function

#define GUARDED_FUNC_TIMER \
    GuardedTimer _long_long_name_guarded_timer(__func__)

#define TOTAL_FUNC_TIMER \
    TotalTimer _long_long_name_total_timer(__func__)
// #endif